﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

using LowLevelGraphics.Types.Interval;
using LowLevelGraphics.Types.Predicates;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// m_r[i].Contains(color.R) OPERATOR m_r[i].Contains(color.G) OPERATOR m_r[i].Contains(color.B)
    /// Define several Thresholds resulting in different colors, based on RGB channel (momentarily)
    /// </summary>
    public class SingleLayerMultiThreshold : BaseImageFilter
    {
        protected ByteInterval[] m_A = null;

        protected ByteInterval[] m_R = new ByteInterval[] { new ByteInterval(0, 127), new ByteInterval(128, 255) };
        protected ByteInterval[] m_G = new ByteInterval[] { new ByteInterval(0, 100), new ByteInterval(101, 255) };
        protected ByteInterval[] m_B = new ByteInterval[] { new ByteInterval(0, 50), new ByteInterval(128, 255) };

        protected IEnumerable<Color> m_aColor = Definitions.KnownColors;

        private BoolOperator m_bOperator1 = BoolOperator.AND;

        protected BoolOperator m_bOperator2 = BoolOperator.AND;
        private delegate void Test(ByteInterval _a, ByteInterval _r, ByteInterval _g, ByteInterval _b);
        private delegate void Test2(ByteInterval _a);

        protected List<Color> aColor = new List<Color>();

        /// <summary>
        /// default constructor
        /// </summary>
        public SingleLayerMultiThreshold()
        {
            foreach (Color colorTemp in m_aColor)
            {
                aColor.Add(colorTemp);
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SingleLayerMultiThreshold"/> class.
        /// </summary>
        /// <param name="_r">The _r.</param>
        /// <param name="_g">The _g.</param>
        /// <param name="_b">The _b.</param>
        public SingleLayerMultiThreshold(ByteInterval[] _r, ByteInterval[] _g, ByteInterval[] _b)
            : this(null, _r, _g, _b)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SingleLayerMultiThreshold"/> class.
        /// </summary>
        /// <param name="_a">The _a.</param>
        /// <param name="_r">The _r.</param>
        /// <param name="_g">The _g.</param>
        /// <param name="_b">The _b.</param>
        public SingleLayerMultiThreshold(ByteInterval[] _a, ByteInterval[] _r, ByteInterval[] _g, ByteInterval[] _b)
            : this()
        {
            m_A = _a;
            m_R = _r;
            m_G = _g;
            m_B = _b;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SingleLayerMultiThreshold"/> class.
        /// </summary>
        /// <param name="_r">The _r.</param>
        /// <param name="_operator1">The _operator1.</param>
        /// <param name="_g">The _g.</param>
        /// <param name="_operator2">The _operator2.</param>
        /// <param name="_b">The _b.</param>
        public SingleLayerMultiThreshold(ByteInterval[] _r, BoolOperator _operator1, ByteInterval[] _g, BoolOperator _operator2, ByteInterval[] _b)
        {
            m_R = _r;
            m_bOperator1 = _operator1;
            m_G = _g;
            m_bOperator2 = _operator2;
            m_B = _b;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SingleLayerMultiThreshold"/> class.
        /// </summary>
        /// <param name="_a">The _a.</param>
        /// <param name="_r">The _r.</param>
        /// <param name="_g">The _g.</param>
        /// <param name="_b">The _b.</param>
        public SingleLayerMultiThreshold(ByteInterval _a, ByteInterval _r, ByteInterval _g, ByteInterval _b)
        {
            m_A = new ByteInterval[] { _a };
            m_R = new ByteInterval[] { _r };
            m_G = new ByteInterval[] { _g };
            m_B = new ByteInterval[] { _b };
        }

        /// <summary>
        /// used by clone to create a deep copy
        /// </summary>
        /// <param name="_singleLayerMultiThreshold"></param>
        internal SingleLayerMultiThreshold(SingleLayerMultiThreshold _singleLayerMultiThreshold)
        {
            this.m_A = _singleLayerMultiThreshold.m_A;
            this.m_R = _singleLayerMultiThreshold.m_R;
            this.m_G = _singleLayerMultiThreshold.m_G;
            this.m_B = _singleLayerMultiThreshold.m_B;
        }

        /// <summary>
        /// Gets or sets bool operator 1
        /// </summary>
        public BoolOperator Operator1
        {
            get { return m_bOperator1; }
            set { m_bOperator1 = value; }
        }

        /// <summary>
        /// Gets or sets bool operator 2
        /// </summary>
        public BoolOperator Operator2
        {
            get { return m_bOperator2; }
            set { m_bOperator2 = value; }
        }

        /// <summary>
        /// Gets or sets A
        /// </summary>
        public ByteInterval[] A
        {
            get { return m_A; }
            set { m_A = value; }
        }

        /// <summary>
        /// Gets or sets R
        /// </summary>
        public ByteInterval[] R
        {
            get { return m_R; }
            set { m_R = value; }
        }

        /// <summary>
        /// Gets or sets G
        /// </summary>
        public ByteInterval[] G
        {
            get { return m_G; }
            set { m_G = value; }
        }

        /// <summary>
        /// Gets or sets B
        /// </summary>
        public ByteInterval[] B
        {
            get { return m_B; }
            set { m_B = value; }
        }

        /// <summary>
        /// Return or set color enumerable
        /// </summary>
        public IEnumerable<Color> Color
        {
            get { return m_aColor; }
            set { m_aColor = value; }
        }

        /// <summary>
        /// Executes this filter
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {

            Color color = System.Drawing.Color.Transparent;

            int nWidth = _bitmap.Width;
            int nHeight = _bitmap.Height;
            int x = 0;
            int y = 0;
            int nIntervalCount = m_R.Length;
            int i = 0;

            bool bFound = false;
            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    color = _bitmap.GetPixel(x, y);
                    bFound = false;
                    for (i = 0; i < nIntervalCount; i++)
                    {
                        if (Evaluate(m_R[i].Contains(color.R), m_bOperator1, m_R[i].Contains(color.G), m_bOperator2, m_R[i].Contains(color.B)))
                        {
                            _bitmap.SetPixel(x, y, aColor[i]);
                            bFound = true;
                            break;
                        }
                    }
                    if (!bFound) _bitmap.SetPixel(x, y, Definitions.Black);
                }

            }
            return _bitmap;
        }

        /// <summary>
        /// Evaluate with set bool operators
        /// </summary>
        /// <param name="_b1"></param>
        /// <param name="_boolOperator1"></param>
        /// <param name="_b2"></param>
        /// <param name="_boolOperator2"></param>
        /// <param name="_b3"></param>
        /// <returns></returns>
        protected bool Evaluate(bool _b1, BoolOperator _boolOperator1, bool _b2, BoolOperator _boolOperator2, bool _b3)
        {
            bool bTemp1 = Definitions.Bool(_b1, _b2, _boolOperator1);
            bool bTemp2 = Definitions.Bool(bTemp1, _b3, _boolOperator2);
            return bTemp2;
        }

        /// <summary>
        /// Use this to create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new SingleLayerMultiThreshold(this);
        }
    }
}
